package my.edu.model.bills.purchase.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import my.edu.common.constant.MessageConstant;
import my.edu.common.constant.OrderConstant;
import my.edu.common.exception.ExpenditureTypeException;
import my.edu.common.exception.SupplierException;
import my.edu.constant.BillsType;
import my.edu.constant.ExpenditureType;
import my.edu.model.bills.purchase.entity.dto.PurchaseSalesExpensesDTO;
import my.edu.model.bills.purchase.entity.vo.PurchaseOrderVO;
import my.edu.model.information.entity.Supplier;
import my.edu.model.information.entity.SupplierPayableBalanceDetail;
import my.edu.model.information.service.ISupplierService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import my.edu.model.bills.purchase.entity.PurchaseSalesExpenses;
import my.edu.model.bills.purchase.mapper.PurchaseSalesExpensesMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class PurchaseSalesExpensesServiceImpl extends ServiceImpl<PurchaseSalesExpensesMapper, PurchaseSalesExpenses> implements IPurchaseSalesExpensesService {

    @Autowired
    private ISupplierService supplierService;
    @Autowired
    private ExpenditureType expenditureType;

    @Override
    @Transactional
    public void saveBatchByDTO(String billsType, List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList, Long noId, Long subjectId, String subjectName) {
        List<PurchaseSalesExpenses> purchaseSalesExpensesList = checkAndSave(billsType, purchaseSalesExpensesDTOList, noId, subjectId, subjectName);
        //新增来往单位应付款
        List<SupplierPayableBalanceDetail> list = getSupplierPayableBalanceDetails(purchaseSalesExpensesList);
        supplierService.addPayableBalanceDetails(list);
    }


    @Override
    @Transactional
    public void updateBatchByDTO(Long orderId, String billsType, List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList, Long noId, Long subjectId, String subjectName) {
        removeByOrderTypeAndId(billsType, List.of(orderId));
        if ( purchaseSalesExpensesDTOList==null||purchaseSalesExpensesDTOList.isEmpty())return;
        List<PurchaseSalesExpenses> souceList = list(Wrappers.<PurchaseSalesExpenses>lambdaQuery().eq(PurchaseSalesExpenses::getSourceDocumentId, noId));
        remove(Wrappers.<PurchaseSalesExpenses>lambdaQuery().eq(PurchaseSalesExpenses::getSourceDocumentId, noId));
        List<PurchaseSalesExpenses> purchaseSalesExpensesList = checkAndSave(billsType, purchaseSalesExpensesDTOList, noId, subjectId, subjectName);
        //更新来往单位应付款
        List<SupplierPayableBalanceDetail> list = getSupplierPayableBalanceDetails(purchaseSalesExpensesList);
        List<Long> idList = souceList.stream().map(PurchaseSalesExpenses::getId).toList();
        supplierService.updatePayableBalanceDetails(idList, list);
    }

    @Transactional
    protected List<PurchaseSalesExpenses> checkAndSave(String billsType, List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList, Long noId, Long subjectId, String subjectName) {
        //支出类型校验
        extractedExpenditureType(purchaseSalesExpensesDTOList);
        //来往单位校验
        extractedSupplier(purchaseSalesExpensesDTOList);
        //设置源单据id
        List<PurchaseSalesExpenses> purchaseSalesExpensesList = purchaseSalesExpensesDTOList.stream()
                .map(i -> {
                    PurchaseSalesExpenses expenses = BeanUtil.copyProperties(i, PurchaseSalesExpenses.class);
                    if (billsType.equals(BillsType.PURCHASE)) {
                        expenses.setSupplierId(subjectId);
                        expenses.setSupplierName(subjectName);
                    } else if (billsType.equals(BillsType.SALES)) {
                        expenses.setCustomerId(subjectId);
                        expenses.setCustomerName(subjectName);
                    }
                    expenses.setBillsType(billsType);
                    expenses.setSourceDocumentId(noId);
                    expenses.setUnpaidExpense(i.getAmount());
                    expenses.setPaymentStatus(OrderConstant.NOT_PAYMENT);
                    return expenses;
                }).toList();
        saveBatch(purchaseSalesExpensesList);
        return purchaseSalesExpensesList;
    }

    @Override
    public void removeByOrderTypeAndId(String billsType, List<Long> ids) {
        List<Long> list = list(Wrappers.<PurchaseSalesExpenses>lambdaQuery()
                .in(PurchaseSalesExpenses::getSourceDocumentId, ids)).stream().map(PurchaseSalesExpenses::getId).toList();
        remove(Wrappers.<PurchaseSalesExpenses>lambdaQuery()
                .in(PurchaseSalesExpenses::getSourceDocumentId, ids)
                .eq(PurchaseSalesExpenses::getBillsType, billsType)
        );
        supplierService.removePayableBalanceDetails(list, BillsType.PurchaseSalesExpenses);
    }

    @Override
    public void getDetail(List<PurchaseOrderVO> records, String type) {
        for (PurchaseOrderVO record : records) {
            getDetail(record, type);
        }
    }

    private void getDetail(PurchaseOrderVO record, String type) {
        record.setPurchaseSalesExpensesDTOList(list(Wrappers.<PurchaseSalesExpenses>lambdaQuery()
                .eq(PurchaseSalesExpenses::getSourceDocumentId, record.getId())
                .eq(PurchaseSalesExpenses::getBillsType, type))
                .stream().map(i -> BeanUtil.copyProperties(i, PurchaseSalesExpensesDTO.class)).toList()
        );

    }

    private List<SupplierPayableBalanceDetail> getSupplierPayableBalanceDetails(List<PurchaseSalesExpenses> purchaseSalesExpensesList) {
        List<SupplierPayableBalanceDetail> list = purchaseSalesExpensesList.stream().map(i -> {
            SupplierPayableBalanceDetail detail = SupplierPayableBalanceDetail.builder()
                    .billsType(BillsType.PurchaseSalesExpenses)
                    .billId(i.getId())
                    .supplierId(i.getSourceContactId())
                    .payableBalance(i.getUnpaidExpense())
                    .build();
            return detail;
        }).toList();
        return list;
    }


    private void extractedExpenditureType(List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList) {
        List<String> expenditureTypeList = expenditureType.getExpenditureType();
        for (PurchaseSalesExpensesDTO dto : purchaseSalesExpensesDTOList) {
            if (!expenditureTypeList.contains(dto.getExpenditureType()))
                throw new ExpenditureTypeException(MessageConstant.CAN_NOT_FOUND_EXPENDITURETYPE);
        }
    }

    private void extractedSupplier(List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList) {
        List<Long> list = purchaseSalesExpensesDTOList.stream().map(PurchaseSalesExpensesDTO::getSourceContactId).toList();
        long count = supplierService.count(Wrappers.<Supplier>lambdaQuery().in(Supplier::getId, list));
        if (count != list.size()) {
            throw new SupplierException(MessageConstant.SalesExpenses_CAN_NOT_FOUND_SUPPLIER);
        }
    }


}

